import { Link } from '@brillout/docpress'
import { JustAMiddleware, IntegrationHelp, Advanced, UiFrameworkExtension } from '../../components'

<IntegrationHelp />

## Vanilla UI tools

To initialize UI vanilla tools (jQuery, tooltips, ...) you can use the <Link href="/onHydrationEnd">`onHydrationEnd()` hook</Link>.

```js
// pages/+onHydrationEnd.js

export default () => {
  // Initializing vanilla JS component libraries, for example tooltips, after hydration.
  tooltip.init(document.querySelectorAll('.tooltip'))
  // Or some vanilla JS modal library
  $('.my-modals').modal()
}
```


## Analytics

To inject external `<script>` tags, you can use:
 - <Link href="/Head" noBreadcrumb />
 - <Link href="/bodyHtmlEnd" />

You can use the <Link href="/client">`+client.js`</Link> file to initialize analytics code.

```js
// pages/+client.js

someAnalyticsLibrary.init(/* ... */)
```

That way you can install tools such as [Google Analytics](https://developers.google.com/analytics), [Plausible](https://plausible.io), or [Segment](https://segment.com).

You can also load and/or initialize analytics code only after the hydration ends by using the <Link href="/onHydrationEnd">+onHydrationEnd</Link> hook.


## Component libraries

Some component libraries need initialization, most notably vanilla component libraries such as Bootstrap.

To initialize code, you can use
 - <Link href="/onHydrationEnd" noBreadcrumb/>
 - <Link href="/client" noBreadcrumb/>

To inject external scripts, you can use:
 - <Link href="/Head" noBreadcrumb/>
 - <Link href="/bodyHtmlEnd" noBreadcrumb/>

Examples:

- <Link href="/vuetify" />
- <Link href="/mantine" />
- <Link href="/daisyui" />
- <Link href="/examples#component-libraries">... more</Link>


## Data fetching

{/* Similar text at https://vike.dev/stores */ }

Instead of using <Link href="/data">the `+data` hook</Link>, you can use <Link href="/data-fetching#tools">tools to fetch the page's initial data</Link>.

<Advanced>
  The following explains how to integrate tools for fetching initial data. Instead of manually integrating tools yourself, we generally recommend using <Link href="/extensions">Vike extensions</Link> such as [`vike-react-apollo`](https://github.com/vikejs/vike-react/tree/main/packages/vike-react-apollo#readme) or [`vike-vue-query`](https://github.com/vikejs/vike-vue/tree/main/packages/vike-vue-query#readme).
</Advanced>

Some data-fetching tools enable you to fetch a page's initial data on a component-level instead of <Link href="/data-fetching#data-hook">using the page-level Vike hook `data()`</Link>

On a high-level, the integration works like this:

1. The initial data of a component is fetched while server-side rendering the component.
1. The initial data is serialized and passed to the client. (So that the client uses the exact same data, avoiding double-fetching and <Link href="/hydration-mismatch">hydration mismatches</Link>.)

> If <Link href="/ssr">SSR is disabled</Link>, then the data is only fetched on the client-side. (The component's data is fetched where the component is loaded and executed.)

Some tools provide utilities to integrate more or less automatically. For example <Link href="/apollo-graphql">Apollo GraphQL</Link> provides many utilities to make integration easy.

A fully manual integration can be done as follows:

1. Determine the initial data on the server side (after SSR) and <Link href="/pageContext#custom">make it available as `pageContext.dataInitial`</Link>.
   > You can configure/initialize the tool's client at <Link href="/onBeforeRenderHtml">`onBeforeRenderHtml()`</Link>:
   > ```js
   > // pages/+onBeforeRenderHtml.js
   >
   > import { init } from 'awesome-data-tool'
   >
   > export function onBeforeRenderHtml(pageContext) {
   >   pageContext.dataClient = init({ someConfiguration: 'value' })
   > }
   > ```
   >
   > You can determine the initially fetched data at <Link href="/onAfterRenderHtml">`onAfterRenderHtml()`</Link>:
   > ```js
   > // pages/+onAfterRenderHtml.js
   >
   > export function onAfterRenderHtml(pageContext) {
   >   pageContext.dataInitial = pageContext.dataClient.getFetchedData()
   > }
   > ```
   >
   > If you use React then you may also need to use <Link href="/Wrapper">`+Wrapper`</Link>:
   > ```js
   > // pages/+Wrapper.jsx
   >
   > import { Provider } from 'awesome-data-tool/react'
   > import { usePageContext } from 'vike-react/usePageContext'
   >
   > export function Wrapper({ children }) {
   >   const pageContext = usePageContext()
   >   return <Provider client={pageContext.dataClient}>{children}</Provider>
   > }
   > ```

1. Make `pageContext.dataInitial` available to the client-side by using <Link href="/passToClient">`passToClient`</Link>.

1. On the client-side, initialize with `pageContext.dataInitial`.
   > Typically at <Link href="/onBeforeRenderClient">`onBeforeRenderClient()`</Link>:
   > ```js
   > // pages/+onBeforeRenderClient.js
   >
   > import { initClient } from 'awesome-data-tool'
   >
   > export function onBeforeRenderClient(pageContext) {
   >   pageContext.dataClient = initClient({ data: pageContext.initialData })
   > }
   > ```

See also:

- <Link href="/examples#data-fetching"/>
- <Link href="/data-fetching" />
- <Link href="/stores" />


## Service workers

You can use the <Link href="/client">`+client.js`</Link> file to initialize [service workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API).

```js
// pages/+client.js

// Initializing a Service Worker
navigator.serviceWorker.register(/* ... */)
```


## Without `vike-{react,vue,solid}`

You can manually integrate React/Vue/Solid (<Link href="/ui-frameworks">or any other UI framework</Link>) yourself:

- <Link href="/react#custom-integration" />
- <Link href="/vue#custom-integration" />
- <Link href="/solid#custom-integration" />

You gain control not only over how React/Vue/Solid is integrated, but also how React/Vue/Solid tools are integrated.

```js
// /renderer/+onRenderHtml.js
// Environment: server

import { escapeInject, dangerouslySkipEscape } from 'vike/server'
// This can be any UI framework (React, Vue, Solid, Svelte, ...)
import renderToHtml from 'some-ui-framework'

export { onRenderHtml }

async function onRenderHtml(pageContext) {
  // `Page` is the `export { Page }` of our +Page.js files;
  // Vike doesn't do anything with `Page` and just makes it available as
  // `pageContext.Page`; we can export any `Page` value we want and do whatever we want with it.
  const { Page } = pageContext

  // We control how we use our UI framework to render our pages to HTML
  const pageHtml = await renderToHtml(Page)

  // We control the entire HTML
  return escapeInject`<html>
    <body>
      <head>
        <!-- Some libraries recommend loading code from a CDN -->
        <script src="https://cdn.example.com/some-library/3.3.7/lib.min.js"></script>
      </head>
      <div id="root">
        ${dangerouslySkipEscape(pageHtml)}
      </div>
    </body>
  </html>`
}
```

```js
// /renderer/+onRenderClient.js
// Environment: browser

export { onRenderClient }

import { hydrateDom } from 'some-ui-framework'

async function onRenderClient(pageContext) {
  // Here we can integrate performance measurement tools, e.g. to measure hydration performance
  const { Page } = pageContext
  // We control how our pages are hydrated
  await hydrateDom(Page)
}
```

See:
- <Link href="/onRenderClient" />
- <Link href="/onRenderHtml" />

Since you control how your pages are rendered, you can use any tool you want without any restrictions.
- Any UI framework (React 16, React 17, Vue 2, Vue 3, petite-vue, Svelte, Solid, Preact, ...)
- Any UI library (Vuex, Redux, Pinia, Relay, Apollo GraphQL, Recoil, ...)
- Any CSS framework (Tailwind CSS, Bulma, Bootstrap, Material Design, ...)
- Any client-side library (Vanilla JS component libraries, Bugsnag, Sentry, jQuery, Google Analytics, ...)
- Any browser technology (Service Workers, PWA, ...)
- Etc.

> The Vike extensions `vike-react`/`vike-vue`/`vike-solid` aim to be almost as flexible. If you reach a limitation you believe is caused by `vike-{react,vue,solid}` then <Link href="/extension-vs-custom">reach out before considering going for a manual integration</Link>.

## See also

- <Link href="/examples" />
